iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
Modern Web

30天學習Tauri系列 第 13

13.實作Tauri Todo -Backend (三) 編寫Tauri Core

  • 分享至 

  • xImage
  •  

接著,我們在todo\src-tauri\src\todo.rs加入create和delete以及done功能

  pub fn new_todo(&self, title: String, date: String) -> bool {
    match self
        .conn
        .execute("INSERT INTO Todo (title, date) VALUES (?, ?)", [title, date])
    {
        Ok(insert) => {
            println!("{} inserted", insert);
            true
        }
        Err(err) => {
            println!("Insert Error: {}", err);
            false
        }
    }
  }

  pub fn done_todo(&self, id: i32) -> bool {
    match self
        .conn
        .execute("UPDATE Todo SET done=1 WHERE id=$1", [id])
    {
        Ok(done) => {
            println!("{} done", done);
            true
        }
        Err(err) => {
            println!("Done Error: {}", err);
            false
        }
    }
  }


  pub fn delete_todo(&self, id: i32) -> bool {
    match self
        .conn
        .execute("DELETE FROM Todo WHERE id=$1", [id])
    {
        Ok(delete) => {
            println!("{} deleted", delete);
            true
        }
        Err(err) => {
            println!("Delete Error: {}", err);
            false
        }
    }
  }

修改new和todo type

use rusqlite::{Connection, Result};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Todo {
  pub id: i32,
  pub title: String,
  pub date: String,
  pub done: bool,
}

pub struct TodoApp {
  pub conn: Connection,
}

impl TodoApp {
  pub fn new()->Result<TodoApp>{
    let db_path = "db.sqlite";
    let conn = Connection::open(db_path)?;
    conn.execute(
        "CREATE TABLE IF NOT EXISTS Todo (
            id          INTEGER PRIMARY KEY   AUTOINCREMENT,
            title       text            NOT NULL,
            date        text            NOT NULL,
            done        numeric         DEFAULT 0
        )",
        [],
    )?;
    Ok(TodoApp { conn })
  }

接著,我們回到main.rs加入我們新添加的方法


    .invoke_handler(tauri::generate_handler![
      get_todos, new_todo, done_todo, delete_todo
    ])


//加入新的tauri命令

#[tauri::command]
fn new_todo(title: String, date: String) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.new_todo(title, date);
  app.conn.close();
  result
}

#[tauri::command]
fn done_todo(id: i32) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.done_todo(id);
  app.conn.close();
  result
}

#[tauri::command]
fn delete_todo(id: i32) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.delete_todo(id);
  app.conn.close();
  result

接著我們刪除db.sqlite

我們接著開始測試pnpm tauri dev並打開devTool

執行create和done指令
console
https://ithelp.ithome.com.tw/upload/images/20220928/2010893157Oq3qC2Aw.png

backend
https://ithelp.ithome.com.tw/upload/images/20220928/20108931UuAxZC2JK0.png

databse
https://ithelp.ithome.com.tw/upload/images/20220928/20108931o8rLriLXIv.png

執行Delete

console
https://ithelp.ithome.com.tw/upload/images/20220928/20108931B1JHkbWAfc.png

backend
https://ithelp.ithome.com.tw/upload/images/20220928/201089315T6Emp1CBX.png

database
https://ithelp.ithome.com.tw/upload/images/20220928/20108931oOr9wjqMap.png


以下是今天完整的程式碼

todo.rs

use rusqlite::{Connection, Result};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Todo {
  pub id: i32,
  pub title: String,
  pub date: String,
  pub done: bool,
}

pub struct TodoApp {
  pub conn: Connection,
}

impl TodoApp {
  pub fn new()->Result<TodoApp>{
    let db_path = "db.sqlite";
    let conn = Connection::open(db_path)?;
    conn.execute(
        "CREATE TABLE IF NOT EXISTS Todo (
            id          INTEGER PRIMARY KEY   AUTOINCREMENT,
            title       text            NOT NULL,
            date        text            NOT NULL,
            done        numeric         DEFAULT 0
        )",
        [],
    )?;
    Ok(TodoApp { conn })
  }
  
  // Get All
  pub fn get_todos(&self) -> Result<Vec<Todo>> {
    let mut stmt = self.conn.prepare("SELECT * FROM Todo").unwrap();
    let todos_iter = stmt.query_map([], |row| {
        let done = row.get::<usize, i32>(3).unwrap() == 1;

        Ok(Todo {
            id: row.get(0)?,
            title: row.get(1)?,
            date: row.get(2)?,
            done,
        })
    })?;
    let mut todos: Vec<Todo> = Vec::new();

    for todo in todos_iter {
        todos.push(todo?);
    }

    Ok(todos)
  }

  pub fn new_todo(&self, title: String, date: String) -> bool {
    match self
        .conn
        .execute("INSERT INTO Todo (title, date) VALUES (?, ?)", [title, date])
    {
        Ok(insert) => {
            println!("{} inserted", insert);
            true
        }
        Err(err) => {
            println!("Insert Error: {}", err);
            false
        }
    }
  }

  pub fn done_todo(&self, id: i32) -> bool {
    match self
        .conn
        .execute("UPDATE Todo SET done=1 WHERE id=$1", [id])
    {
        Ok(done) => {
            println!("{} done", done);
            true
        }
        Err(err) => {
            println!("Done Error: {}", err);
            false
        }
    }
  }


  pub fn delete_todo(&self, id: i32) -> bool {
    match self
        .conn
        .execute("DELETE FROM Todo WHERE id=$1", [id])
    {
        Ok(delete) => {
            println!("{} deleted", delete);
            true
        }
        Err(err) => {
            println!("Delete Error: {}", err);
            false
        }
    }
  }
}

main.rs

#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use std::sync::Mutex;
use tauri::{CustomMenuItem, Menu, MenuItem, Submenu, Manager};

mod todo;
use todo::{Todo, TodoApp};

struct AppState {
  app: Mutex<TodoApp>,
}

fn main() {
  let app = TodoApp::new().unwrap();
  // here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label.
  let quit = CustomMenuItem::new("quit".to_string(), "Quit");
  let close = CustomMenuItem::new("close".to_string(), "Close");
  let submenu = Submenu::new("Custom", Menu::new().add_item(quit).add_item(close));
  let menu = Menu::new()
    .add_native_item(MenuItem::Copy)
    .add_item(CustomMenuItem::new("hide", "Hide"))
    .add_submenu(submenu);

  tauri::Builder::default()
    .setup(|app| {
      let splashscreen_window = app.get_window("splashscreen").unwrap();
      let main_window = app.get_window("main").unwrap();
      // we perform the initialization code on a new task so the app doesn't freeze
      tauri::async_runtime::spawn(async move {
        // initialize your app here instead of sleeping :)
        println!("Initializing...");
        std::thread::sleep(std::time::Duration::from_secs(5));
        println!("Done initializing.");

        // After it's done, close the splashscreen and display the main window
        splashscreen_window.close().unwrap();
        main_window.show().unwrap();
      });
      Ok(())
    })
    .menu(menu)
    .on_menu_event(|event| match event.menu_item_id() {
      "quit" => {
        // Custom
        std::process::exit(0);
      }
      "close" => {
        // Custom
        event.window().close().unwrap();
      }
      "hide" => {
        println!("Hide Click");
      }
      _ => {}
    })
    .invoke_handler(tauri::generate_handler![
      get_todos, new_todo, done_todo, delete_todo
    ])
    .manage(AppState {
        app: Mutex::from(app),
    })
    .run(tauri::generate_context!())
    .expect("failed to run app");
}

#[tauri::command]
fn get_todos(state: tauri::State<AppState>) -> Vec<Todo> {
    let app = state.app.lock().unwrap();
    let todos = app.get_todos().unwrap();
    todos
}

#[tauri::command]
fn new_todo(title: String, date: String) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.new_todo(title, date);
  app.conn.close();
  result
}

#[tauri::command]
fn done_todo(id: i32) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.done_todo(id);
  app.conn.close();
  result
}

#[tauri::command]
fn delete_todo(id: i32) -> bool {
  let app = TodoApp::new().unwrap();
  let result = app.delete_todo(id);
  app.conn.close();
  result
}

!!Bug:這裡有時候會出現App會一直重啟的問題,尋找後,發現可能是tauri會觀察你的目錄是否有變化並且會重啟。(Solve)解決方法是新增.taurignore./src./src-tauri的目錄下,並在.taurignore加入

*

!src/**/*
!src-tauri/**/*

我們今天簡單的完成了新增、修改和刪除的指令。明天開始將backend和frontend結合


上一篇
12.實作Tauri Todo -Backend (二) 編寫Tauri Core
下一篇
14.實作Tauri Todo -Frontend (一) 編寫Tauri Todo UI
系列文
30天學習Tauri30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言